package com.liesheng.haylou.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.util.Log;

import com.liesheng.daemonlib.LogUtil;
import com.liesheng.haylou.R;
import com.liesheng.haylou.common.MainHandler;
import com.liesheng.haylou.event.BleScanEvent;
import com.liesheng.haylou.utils.NumUtil;
import com.liesheng.haylou.utils.ToastUtil;

import org.greenrobot.eventbus.EventBus;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;

/**
 * Date:2019/12/3
 * <p>
 * Author:wuzhiguang
 * <p>
 * Description:
 * ble 操作类
 */
public class BleManager {

    public static final long SCAN_DURING = 10 * 1000; //扫描6秒后停止

    private static BleUtil bleUtil;

    private static BleManager instance;

    private boolean isScanning = false;

    private List<BluetoothAdapter.LeScanCallback> callbacks = new ArrayList<>();

    private BleGattConnectListener gattConnectListener;

    private HashMap<String, BluetoothGatt> gatts = new HashMap<>();

    private HashMap<String, String> addresses = new HashMap<>();

    private BleManager() {
        bleUtil = new BleUtil();
    }

    public static BleManager getInstance() {
        if (instance == null)
            instance = new BleManager();
        return instance;
    }

    public boolean isBluetoothOpen(){
        return bleUtil.isBluetoothOpen();
    }

    //通知蓝牙地址获取对应的BluetoothGatt,返回空代表未连接
    public BluetoothGatt getBluetoothGatt(String address){
        return gatts.get(address);
    }

    public void scanBle(final BluetoothAdapter.LeScanCallback scanCallback) {
        if(!bleUtil.isBluetoothOpen()){

        }

        if (isScanning) {
            stopScan();
            isScanning = false;
        }

        bleUtil.scanBle(scanCallback);
        callbacks.add(scanCallback);
        isScanning = true;
        Observable.timer(SCAN_DURING, TimeUnit.MILLISECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        bleUtil.stopScan(scanCallback);
                        isScanning = false;
                        EventBus.getDefault().post(new BleScanEvent());
                    }
                });
    }

    //写
    public void write(String rLAddress, String characteristicUuid, String value) {
        LogUtil.d("--onWrite","uuid = "+characteristicUuid +"         value ="+value);
        BluetoothGatt gatt = gatts.get(rLAddress);
        if (gatt == null) {
            ToastUtil.showToast(R.string.ble_not_conn);
            return;
        }
        BluetoothGattService service = gatt.getService(UUID.fromString(BleUUIDs.SERVICE));
        if (service == null) {
            ToastUtil.showToast(R.string.ble_no_service);
            return;
        }
        BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicUuid));//通过UUID获取可读的Characteristic
        characteristic.setValue(NumUtil.hexToBytes(value));
        gatt.writeCharacteristic(characteristic);
    }

    //读
    public void read(String rLAddress, String characteristicUuid) {
        BluetoothGatt gatt = gatts.get(rLAddress);
        if (gatt == null) {
            ToastUtil.showToast(R.string.ble_not_conn);
            return;
        }
        BluetoothGattService service = gatt.getService(UUID.fromString(BleUUIDs.SERVICE));
        if (service == null) {
            ToastUtil.showToast(R.string.ble_no_service);
            return;
        }

        BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicUuid));//通过UUID获取可读的Characteristic
        if (characteristic == null) {
            ToastUtil.showToast("没有该characteristic");
            return;
        }
        gatt.readCharacteristic(characteristic);
    }

    // 设置通知Characteristic变化会回调->onCharacteristicChanged()
    public void setNotify(String rLAddress, String characteristicUuid) {
        BluetoothGatt gatt = gatts.get(rLAddress);
        if (gatt == null) {
            ToastUtil.showToast(R.string.ble_not_conn);
            return;
        }
        BluetoothGattService service = gatt.getService(UUID.fromString(BleUUIDs.SERVICE));
        if (service == null) {
            ToastUtil.showToast(R.string.ble_no_service);
            return;
        }

        // 设置Characteristic通知
        BluetoothGattCharacteristic characteristic = service.getCharacteristic(UUID.fromString(characteristicUuid));//通过UUID获取可通知的Characteristic
        gatt.setCharacteristicNotification(characteristic, true);

        // 向Characteristic的Descriptor属性写入通知开关，使蓝牙设备主动向手机发送数据
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(BleUUIDs.DESC_CHAR_STATUS1));
        // descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);//和通知类似,但服务端不主动发数据,只指示客户端读取数据
        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        gatt.writeDescriptor(descriptor);
    }


    //连接ble
    public void connect(String rLAddress, BleGattConnectListener gattConnectListener) {
        if (gatts.get(rLAddress) != null) {
            this.gattConnectListener = gattConnectListener;
            gattConnectListener.onConnect();
        }else {
            gattConnectListener.onDisConnect();
        }
    }

    public void connect(String rLAddress, BluetoothDevice device, BleGattConnectListener gattConnectListener) {
        this.gattConnectListener = gattConnectListener;
        if (gatts.get(rLAddress) != null) {
            gattConnectListener.onConnect();
            return;
        }
        addresses.put(device.getAddress(),rLAddress);
//        closeConn();
        bleUtil.connect(device, gattCallback);
    }

    private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            //连接成功
            if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
                gatt.discoverServices(); //启动服务发现
            } else {//连接失败/断开连接
                gatts.put(addresses.get(gatt.getDevice().getAddress()), null);
                MainHandler.getInstance().post(new Runnable() {
                    @Override
                    public void run() {
                        gattConnectListener.onDisConnect();
                    }
                });
            }
        }

        //发现服务
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                gatts.put(addresses.get(gatt.getDevice().getAddress()), gatt);

                for (BluetoothGattService service:gatt.getServices()){
                    Log.d("onServicesDiscovered","service--uuid = "+service.getUuid());
                }

                MainHandler.getInstance().post(new Runnable() {
                    @Override
                    public void run() {
                        gattConnectListener.onConnect();
                    }
                });
            }
        }

        //读取
        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {


            MainHandler.getInstance().post(new Runnable() {
                @Override
                public void run() {
                    String uuid = characteristic.getUuid().toString();
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        String value = NumUtil.bytesToHex(characteristic.getValue());
                        gattConnectListener.onRead(0, uuid, value);
                    } else {
                        gattConnectListener.onRead(status, uuid, "read failed");
                    }
                }
            });

        }

        //写入
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) {

            MainHandler.getInstance().post(new Runnable() {
                @Override
                public void run() {
                    String uuid = characteristic.getUuid().toString();
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        gattConnectListener.onWrite(0, uuid);
                        String valueStr = new String(characteristic.getValue());
                    } else {
                        gattConnectListener.onWrite(status, uuid);
                    }
                }
            });

        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {

            MainHandler.getInstance().post(new Runnable() {
                @Override
                public void run() {
                    String uuid = characteristic.getUuid().toString();
                    String value = NumUtil.bytesToHex(characteristic.getValue());
                    gattConnectListener.onNotify(uuid,value);
                }
            });

        }
    };


    public void stopScan() {
        for (BluetoothAdapter.LeScanCallback callback : callbacks) {
            bleUtil.stopScan(callback);
            callback = null;
        }
        callbacks.clear();
    }

    public void closeConn(String address) {
        bleUtil.closeConn(gatts.get(address));
        gatts.put(address,null);
    }

    public void closeAllConn() {
        for (BluetoothGatt gatt : gatts.values()) {
            bleUtil.closeConn(gatt);
        }
    }

}
